package com.ocom.payhandle.config.datasource;

import com.alibaba.druid.pool.DruidDataSource;
import com.ocom.common.entity.master.EntityCompanyPart;
import com.ocom.common.enums.DataSourceEnum;
import com.ocom.common.enums.MasterSlaveEnum;
import com.ocom.common.utils.SpringUtils;
import com.ocom.mysql.DataSourceHolder;
import com.ocom.mysql.DynamicDataSource;
import com.ocom.mysql.aspect.DataSourceAspect;
import com.ocom.payhandle.service.CompanyPartService;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.CodeSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.context.config.annotation.RefreshScope;
import org.springframework.core.annotation.Order;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Component;

import javax.sql.DataSource;
import java.util.HashMap;
import java.util.Map;

/**
 * 描述:通过@Aspect注解使该类成为切面类
 */
@Aspect
//保证在事务前
@Order(value = -1)
@Component
@RefreshScope
public class DataSourceAspectImpl {

    static DataSourcePool pool = new DataSourcePool(30);

    @Autowired
    JdbcTemplate jdbcTemplate;

    @Autowired
    CompanyPartService companyPartService;

    @Pointcut("@annotation(com.ocom.mysql.aspect.DataSourceAspect)")
    private void cut() {
    }

    //运行时切面 切换数据源
    @Around("cut() && @annotation(dataSourceAspect)")
    public Object around(ProceedingJoinPoint point, DataSourceAspect dataSourceAspect) throws Throwable {
        DataSourceEnum dataSourceEnum = dataSourceAspect.type();
        MasterSlaveEnum masterSlaveEnum = dataSourceAspect.isMaster();


        if (dataSourceEnum != null) {
            if (dataSourceEnum == DataSourceEnum.MAIN_DB) {
                //主库
                if(masterSlaveEnum==MasterSlaveEnum.MASTER){
                    DynamicDataSource.setDataSource((DataSource) SpringUtils.getBean("defaultDataSource"));
                }else{
                    DynamicDataSource.setDataSource((DataSource) SpringUtils.getBean("defaultDataSourceSlave"));
                }
                try {
                    return point.proceed();
                } finally {
                    DataSourceHolder.clearDataSourceKey();
                }
            } else {
                //分库 未加缓存 TODO
                //方法的参数和值
                Map<String, Object> params = getNameAndValue(point);
                //是否存在要判断的键
                boolean containsKey = params.containsKey(dataSourceAspect.companyId());
                String comId="companyId";
                if(containsKey) {
                    comId = dataSourceAspect.companyId();
                }
                Long companyId=(Long) params.get(comId);
                EntityCompanyPart entityCompanyPart=null;
                if (masterSlaveEnum == MasterSlaveEnum.MASTER)
                    entityCompanyPart = companyPartService.getCompanyDataSource(companyId, 1, 1);
                else
                    entityCompanyPart = companyPartService.getCompanyDataSource(companyId, 1, 0);


                if(entityCompanyPart==null){
                    throw new RuntimeException("没有相应数据源");
                }
                DruidDataSource dataSource=pool.fetchConnection(entityCompanyPart,2000);

                DynamicDataSource.setDataSource(dataSource);
                try {
                    return point.proceed();
                } finally {
                    DataSourceHolder.clearDataSourceKey();
                    pool.releaseConnection(dataSource);
                }
            }
        } else {
            // 条件为假 取默认数据源
            DynamicDataSource.setDataSource((DataSource) SpringUtils.getBean("defaultDataSource"));
            try {
                return point.proceed();
            } finally {
                DataSourceHolder.clearDataSourceKey();
            }
        }
    }



    /**
     * 获取参数Map集合
     * @param joinPoint
     * @return
     */
    Map<String, Object> getNameAndValue(ProceedingJoinPoint joinPoint) {
        Map<String, Object> param = new HashMap<>();
        Object[] paramValues = joinPoint.getArgs();
        String[] paramNames = ((CodeSignature)joinPoint.getSignature()).getParameterNames();
        for (int i = 0; i < paramNames.length; i++) {
            param.put(paramNames[i], paramValues[i]);
        }
        return param;
    }






}